import java.util.ArrayList;
import java.util.Arrays;

public class ControlStructure {

	ST st;
	ArrayList<ControlElement> delta[];

	/*
	 * +1 for delta zero
	 */
	public ControlStructure(ST st) {
		this.st = st;
		int lambdaCount = countLambda(st.stRoot) + 1;
		phase2(lambdaCount);
	}

	int deltaTop;
	/*
	 * use a newDeltaAllocate value and pass
	 */
	private void phase2(int lambdaCount) {
		delta = (ArrayList<ControlElement>[])new ArrayList[lambdaCount];
		delta[0] = new ArrayList<ControlElement>();
		generateControl(deltaTop, st.stRoot);
	}

	@Override
	public String toString() {
		String str = "";
		for(int i = 0 ; i < delta.length ; i++){
			str += i + ": ";
			 for(int j = 0; j < delta[i].size() ; j++){
				 str += delta[i].get( j ) + " ";
			 }
			 str += "\n";
		}
		return str;
	}

	/*
	 * Call with the deltaCounter where you want to add
	 */
	private void generateControl(int pointer, STNode root) {
		if (root.content.equals("lambda")){
			handleLambda(pointer, root);
		}else if (root.content.equals("tau")){
			handleTau(pointer, root);
		}else if (root.content.equals("->")){
			handleCondition(pointer, root);
		}else if (root.content.equals(",")){
			// lambda will handle it
			assert(false):"generateControl: state should not be reached";
		}else if (isTerminal(root)){
			delta[pointer].add(new ControlElement(root.content));
		}else if (isUnaryOp(root)){
			delta[pointer].add(new ControlElement(root.content));
			generateControl(pointer, root.childArray[0]);
		}else if (root.content.equals("@")){
			assert(root.childArray.length == 3):"generateControl: @ must have three children";
			delta[pointer].add(new ControlElement(root.content));
			generateControl(pointer, root.childArray[0]);
			generateControl(pointer, root.childArray[1]);
			generateControl(pointer, root.childArray[2]);
		}else{
			delta[pointer].add(new ControlElement(root.content));
			generateControl(pointer, root.childArray[0]);
			generateControl(pointer, root.childArray[1]);
		}
	
	}
	
	private boolean isUnaryOp(STNode root) {
		if (root.content.equals("neg")|
				root.content.equals("not"))
			return true;
		else
			return false;
	}

	private void handleCondition(int pointer, STNode root) {
		assert(root.childArray.length == 3):"handleCondition: -> must have three children";
		STNode boolExp = root.childArray[0];
		STNode trueStat = root.childArray[1];
		STNode falseStat = root.childArray[2];
		
		//deltathan
		deltaTop++;
		delta[deltaTop] = new ArrayList<ControlElement>();
		delta[pointer].add(new ControlCondition("deltaTrue",deltaTop));
		generateControl(deltaTop, trueStat);
		
		//deltaelse
		deltaTop++;
		delta[deltaTop] = new ArrayList<ControlElement>();
		delta[pointer].add(new ControlCondition("deltaFalse",deltaTop));
		generateControl(deltaTop, falseStat);
		
		
		delta[pointer].add(new ControlElement("beta"));
		generateControl(pointer, boolExp);
	}

	private void handleTau(int pointer, STNode root) {
		ControlTau tau = new ControlTau("tau", root.childArray.length);
		delta[pointer].add(tau);
		for(int i = 0 ; i < root.childArray.length ; i ++){
			generateControl(pointer, root.childArray[i]);
		}
	}

	private boolean isTerminal(STNode root) {
		if (root.content.contains("<ID:") |
				root.content.contains("<INT:")|
				root.content.contains("<STR:")|
				root.content.equals("<Y*>") |
				root.content.equals("<nil>") |
				root.content.equals("<dummy>") |
				root.content.equals("<true>") |
				root.content.equals("<false>") ){
			
			assert(root.childArray.length == 0):"terminal cannot have any children";
			return true;
		}
		return false;
	}

	/*
	 * either lambda will have a definition or a common ','
	 * common (x,y,z) have to be simple <id> list thats all
	 * <lambda:counter to its array:variables
	 */
	private void handleLambda(int deltaPointer, STNode root) {
		assert(root.childArray.length==2):"lamnda must have child length of two";
		deltaTop++;
		int newTop = deltaTop;
		STNode leftChild = root.childArray[0];
		STNode rightChild = root.childArray[1];
		
		ControlLambda lambda = new ControlLambda(newTop,leftChild);
		delta[deltaPointer].add(lambda);

		delta[newTop] = new ArrayList<ControlElement>();
		generateControl(newTop, rightChild);
	}

	
	private int countLambda(STNode pointer) {
		int counter = 0;
		if (pointer.childArray.length == 0)
		{
			assert(!pointer.content.equals("lambda")): "lambda must have two children";
			return 0;
		}else if (pointer.content.equals("lambda")){
			counter += 1;
		}else if (pointer.content.equals("->")){
			counter += 2;
		}
		for(int i = 0 ; i < pointer.childArray.length ; i++){
			counter += countLambda(pointer.childArray[i]); 
		}
		return counter;
	}

	public static void main(String[] args) {
		p1 parser = new p1("c:\\matrix_order1");
		ST st = new ST();
		
		st.astRoot = parser.getASTTree();
		st.stRoot = st.standardize(st.astRoot);
		//System.out.println("----------");
		//st.stRoot.print(0);
		
		ControlStructure ct = new ControlStructure(st);
		System.out.println(ct);
			
	}

}
